#include "RootFinderEnvironment.h"

template <typename T>
Environment* RootFinderEnvironment<T>::getEnvironment()
{
    return new RootFinderEnvironment<ValueEncodedSolution<int> >();
}

template <typename T>
RootFinderEnvironment<T>::RootFinderEnvironment()
{
    throw Unsupported_template_exception();
}

RootFinderEnvironment<ValueEncodedSolution<int> >::RootFinderEnvironment()
{
    variableCount = 2;
    vector<double> powers;
    powers.push_back(2);
    powers.push_back(4);
    Term<int> newTerm(3, powers);
    terms.push_back(newTerm);
    powers.clear();
    
    powers.push_back(1);
    powers.push_back(5);
    Term<int> newTerm2(7, powers);
    terms.push_back(newTerm2);
}

template <typename T>
void RootFinderEnvironment<T>::configure()
{
}

double RootFinderEnvironment<ValueEncodedSolution<int> >::evaluateTerms(Solution *solution)
{
    double total = 0;
    
    ValueEncodedSolution<int>* vesSolution = (ValueEncodedSolution<int>*) solution;
    
    for (unsigned int i = 0; i < terms.size(); ++i)
        total += terms[i].evaluate(vesSolution->getSolution());
    
    return total;
}

double RootFinderEnvironment<ValueEncodedSolution<int> >::evaluateFitness(Solution *solution)
{
    double total = evaluateTerms(solution);
    return abs(total) * -1;
}

string RootFinderEnvironment<ValueEncodedSolution<int> >::formatSolution(Solution *solution)
{
    ValueEncodedSolution<int> *vesSolution = (ValueEncodedSolution<int>*) solution->clone();
    ostringstream output;
    for (unsigned int i = 0; i < terms.size(); ++i)
        output << terms[i].toString(vesSolution->getSolution()) << ' ';
        
    output << " = " << evaluateTerms(solution);
    output << " : " << evaluateFitness(solution);

    return output.str();
}

void RootFinderEnvironment<ValueEncodedSolution<int> >::generateRandomPopulation(vector<Solution*> &solutions, unsigned int populationSize)
{
    for (unsigned int i = 0; i < populationSize; ++i)
    {
        ValueEncodedSolution<int> *newSolution = new ValueEncodedSolution<int>();
        
        //TODO: figure out how to determine these ranges
        newSolution->fillWithRandomSolution(variableCount, -10, 10);
        newSolution->setFitness(evaluateFitness(newSolution));
        solutions.push_back(newSolution);
    }
}

template <typename T>
Crossover* RootFinderEnvironment<T>::configureCrossover()
{    int choice = 0;
    cout << "What kind of crossover method do you wish to use?" << endl;
    cout << " (1) Single Point" << endl;
    cout << " (2) Two Point" << endl;
    cout << " (3) Random" << endl;
    
    while (true)
    {
	    cout << "? ";
	    cin >> choice;
	    
	    switch(choice)
	    {
	        case 1: 
	            return new SinglePointCrossover<ValueEncodedSolution<int> >();
	 //       case 2:
	  //      	return new TwoPointCrossover<ValueEncodedSolution<int> >();
	        case 3:
	        	return new RandomGenerationCrossover(this);
	        default: 
	        {
	        	cout << "Invalid selection." << endl;
	        	break;
	        }
	    }
    }
}

template class RootFinderEnvironment<ValueEncodedSolution<int> >;
